package com.qcsec.controller;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.exception.SaTokenException;
import com.alibaba.fastjson2.JSON;
import com.qcsec.common.base.RestResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author wenbo
 */
@ApiIgnore
@RestControllerAdvice
@Slf4j
public class ExceptionController {
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestResp<?> handleValidationExceptions(MethodArgumentNotValidException ex) {
        StringBuilder errors = new StringBuilder();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.append(String.format("【%s】 => 【%s】; ", fieldName, errorMessage));
        });
        return RestResp.fail(HttpStatus.BAD_REQUEST.value(), errors.toString());
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(DataAccessException.class)
    public RestResp<?> handleSQLExceptions(DataAccessException ex) {
        log.error("DataAccessException: {}", ex.getMessage(), ex);
        return RestResp.fail("数据操作失败");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public RestResp<?> handleViolationException(ConstraintViolationException exception) {
        Set<ConstraintViolation<?>> violations = exception.getConstraintViolations();
        StringBuilder builder = new StringBuilder();
        for (ConstraintViolation<?> violation : violations) {
            Iterator<Path.Node> iterator = violation.getPropertyPath().iterator();
            while (iterator.hasNext()) {
                Path.Node node = iterator.next();
                if (!iterator.hasNext()) {
                    builder.append(String.format("【%s】 => 【%s】;", node.getName(), violation.getMessage()));
                }
            }
        }
        return RestResp.fail(HttpStatus.BAD_REQUEST.value(), builder.toString());
    }

    @ExceptionHandler(NotLoginException.class)
    public RestResp<?> notLoginException(HttpServletRequest req, Throwable e) {
        String servletPath = req.getServletPath();
        Map<String, String[]> parameterMap = req.getParameterMap();
        log.error("请求路由: {}  , 请求参数: {} , token失效！！！ ",servletPath, JSON.toJSONString(parameterMap),e);
        return RestResp.fail(e,"token失效");
    }
    @ExceptionHandler(NotPermissionException.class)
    public RestResp<?> notPermissionException(HttpServletRequest req, Throwable e) {
        String servletPath = req.getServletPath();
        Map<String, String[]> parameterMap = req.getParameterMap();
        log.error("请求路由: {}  , 请求参数: {} , 无权限！！！ ",servletPath, JSON.toJSONString(parameterMap),e);
        return RestResp.fail(e,"无权限");
    }

    @ExceptionHandler(NotRoleException.class)
    public RestResp<?> notRoleException(HttpServletRequest req, Throwable e) {
        String servletPath = req.getServletPath();
        Map<String, String[]> parameterMap = req.getParameterMap();
        log.error("请求路由: {}  , 请求参数: {} , 角色不匹配！！！ ",servletPath, JSON.toJSONString(parameterMap),e);
        return RestResp.fail(e,"角色不匹配");
    }

    @ExceptionHandler(SaTokenException.class)
    public RestResp<?> saTokenException(HttpServletRequest req, Throwable e) {
        String servletPath = req.getServletPath();
        Map<String, String[]> parameterMap = req.getParameterMap();
        log.error("请求路由: {}  , 请求参数: {} , 认证授权异常！！！ ",servletPath, JSON.toJSONString(parameterMap),e);
        return RestResp.fail(e,"认证授权异常");
    }

    @ExceptionHandler(Throwable.class)
    public RestResp<?> defaultExceptions(HttpServletRequest req, Throwable e) {
        String servletPath = req.getServletPath();
        Map<String, String[]> parameterMap = req.getParameterMap();
        log.error("请求路由: {}  , 请求参数: {} , 执行错误！！！ ",servletPath, JSON.toJSONString(parameterMap),e);
        return RestResp.fail(e,"error");
    }
}
